package com.hexiang.service;

import com.hexiang.DemoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;

import javax.annotation.Resource;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@Service
@Slf4j
public class DemoConsumerService {

    @DubboReference(timeout = 2000,retries = 1,methods = {@Method(name = "timeout",retries = 1, timeout = 4000)})
    private DemoService demoService;

    @DubboReference(methods = {@Method(name = "asyncTimeout", async = true,timeout = 10000)})
    private DemoService asyncDemoService;

    @Resource
    private ThreadPoolTaskExecutor callbackExecutor;


    public String sayHello(String name) {
        log.info("sayHelloStart,name={}", name);
        return demoService.sayHello(name);
    }


    public String timeOut(String name) {
        return demoService.timeout(name);
    }

    public DeferredResult<String> asyncTimeOut(String name) {
        log.info("asyncTimeOutStart,name={}", name);

        DeferredResult<String> deferredResult = new DeferredResult<>();
        // 调用直接返回CompletableFuture
        CompletableFuture<String> future = asyncDemoService.asyncTimeout(name);
        // 增加回调
        future.whenComplete((v, e) -> {
            if (e != null) {
                log.error("asyncTimeOutErr", e);
                deferredResult.setResult("err");

            } else {
                log.info("asyncTimeOutEnd,Response={}", v);
                deferredResult.setResult(v);
            }

        });
        // 早于结果输出
        log.info("Executed before response return.");

        return deferredResult;
    }

    public String asyncSayHello(String name) {
        log.info("asyncSayHelloStart,name={}", name);

        Future<String> future = RpcContext.getContext().asyncCall(() -> asyncDemoService.sayHello(name));
        String result = null;
        try {
            result = future.get();
        } catch (InterruptedException e) {
            log.error("InterruptedException", e);
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            log.error("asyncSayHelloErr", e);
        }
        log.info("asyncSayHelloEnd,result={}", result);
        return result;
    }

    public DeferredResult<String> asyncCallSayHelloAsyncCompletableFuture(String name) {
        log.info("asyncCallSayHelloAsyncCompletableFutureStart,name={}", name);

        DeferredResult<String> deferredResult = new DeferredResult<>();

        // 调用直接返回CompletableFuture
        CompletableFuture<String> future = asyncDemoService.sayHelloAsync(name);
        // 增加回调
        future.whenComplete((v, e) -> {
            if (e != null) {
                log.error("asyncCallSayHelloAsyncCompletableFutureErr", e);
                deferredResult.setResult("err");

            } else {
                log.info("asyncCallSayHelloAsyncCompletableFutureEnd,Response={}", v);
                deferredResult.setResult(v);
            }
        });
        // 早于结果输出
        log.info("Executed before response return.");

        return deferredResult;
    }

    public DeferredResult<String> asyncCallSayHelloCompletableFuture(String name) {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        log.info("asyncCallSayHelloCompletableFutureStart,name={}", name);

        // 调用直接返回CompletableFuture
        CompletableFuture<String> future = asyncDemoService.sayHelloCompletableFuture(name);
        // 增加回调
        future.whenCompleteAsync((v, e) -> {
            if (e != null) {
                log.error("asyncCallSayHelloCompletableFutureErr",e);
                deferredResult.setResult("err");

            } else {
                log.info("asyncCallSayHelloCompletableFutureEnd,Response={}", v);
                deferredResult.setResult(v);
            }
        },callbackExecutor);
        // 早于结果输出
        log.info("Executed before response return.");

        return deferredResult;
    }

    public String asyncCallbackSayHello(String name) {
        log.info("asyncCallbackSayHelloStart,name={}", name);

        CompletableFuture<String> future = RpcContext.getContext().asyncCall(() -> asyncDemoService.sayHello(name));
        String result = "fail";
        try {
            result = future.get();
        } catch (InterruptedException e) {
            log.error("InterruptedException", e);
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            log.error("asyncCallbackSayHelloErr", e);
        }
        log.info("asyncCallbackSayHelloEnd,result={}", result);
        return result;
    }

    public String asyncCallErr(String name){
        log.info("asyncCallErrStart,name={}", name);

        String result = "fail";
        // dubbo服务调用前，通过RpcContext动态设置本次调用的重试次数
        RpcContext rpcContext = RpcContext.getContext();
        rpcContext.setAttachment("retries", 5);

        Future<String> future=  RpcContext.getContext().asyncCall(()->demoService.err(name));
        try {
            result = future.get();
        } catch (InterruptedException e) {
            log.error("InterruptedException", e);
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            log.error("asyncCallbackSayHelloErr", e);
        }
        log.info("asyncCallErrEnd,result={}", result);
        return result;
    }


}